R shiny - 101

2023-06-12

Disclaimer

homer

But I’m happy to help!

Highly inspired by Mastering Shiny 1 book

Shiny

«It is an open source R package that provides an elegant and powerful web framework for building web applications using R» - Rstudio website

  • «A web application is application software that is accessed using a web browser. Web applications are delivered on the World Wide Web to users with an active network connection» - (Wikipedia)

Structure

1library(shiny)

2ui <- fluidPage(

)

3server <- function(input, output) {

}

4shinyApp(ui = ui, server = server)
1
Scripting (load packages, data, …)
2
Front end, to define the user interface
3
Back end, to define the server logic
4
Simply run the application

User Interface

  • Inputs1: functions use to insert input controls into your UI specification
    • inputId argument: identifier to connect the front end with the back end (e.g. if inputId = 'name', the server function will access it with input$name)
    • label argument: title of your input in the user interface
ui <- fluidPage(
  numericInput(inputId = "num", 
               label = "Number one", 
               value = 0, min = 0, max = 100)
)

User Interface

  • Outputs1: functions use to insert placeholders that are later filled by the server function
    • outputId argument: identifier to connect the front end with the back end (e.g. if outputId = 'plot', the server function will update it with output$plot)
    • Each output function on the front end is coupled with a render function in the back end2.
ui <- fluidPage(
  plotOutput(outputId = "plot")
)
server <- function(input, output, session) {
  output$plot <- renderPlot(plot(1:5))
}

Server Logic

writing a script vs. reactive programming

«The key idea of reactive programming is to specify a graph of dependencies so that when an input changes, all related outputs are automatically updated»1

Server Logic

  • the server() function
    • take three parameters: input, output and session
    • since you never call the server() function yourself, you’ll never create these objects yourself

Server Logic

  • the input argument
    • list-like object that contains all the input data sent from the user interface
    • To read from an input, you must be in a reactive context created by a function like renderText()
ui <- fluidPage(
  numericInput(inputId = "count", 
               label = "Number of values", 
               value = 100)
)
server <- function(input, output, session) {
  message("The value of input$count is ", input$count)
}

shinyApp(ui, server)
#> Error: Can't access reactive value 'count' outside of reactive consumer.
#> ℹ Do you need to wrap inside reactive() or observer()?

Server Logic

  • the input argument
    • list-like object that contains all the input data sent from the user interface
    • To read from an input, you must be in a reactive context created by a function like renderText()
ui <- fluidPage(
  numericInput(inputId = "count", 
               label = "Number of values", 
               value = 100),
  textOutput(outputId = "message")
)
server <- function(input, output, session) {
  output$message("The value of input$count is ", input$count)
}

shinyApp(ui, server)

Server Logic

  • the output argument
  • it’s also a list-like object named according to the output ID
  • it’s used for sending output instead of receiving input
  • always use the output object in concert with a render() function
ui <- fluidPage(
  textOutput("greeting")
)

server <- function(input, output, session) {
  output$greeting <- renderText("Hello human!")
}

Practice

The dataset

       id            datetime dive_number dive_type depth
1 2010023 2010-03-10 12:25:01           1    Forage     0
2 2010023 2010-03-10 12:25:03           1    Forage     0
3 2010023 2010-03-10 12:25:06           1    Forage     0
4 2010023 2010-03-10 12:25:08           1    Forage     0
5 2010023 2010-03-10 12:25:10           1    Forage     0
6 2010023 2010-03-10 12:25:11           1    Forage     0

Practice

The plot

1data_tdr %>%
2  ggplot(
3    aes(x = datetime,
4        y = depth)) +
5  geom_path()
1
from data_tdr dataset
2
initiate a plot
3
with the datetime column used for the x-axis
4
and the depth column for the y-axis
5
then specify the type of plot, here a line plot

Practice

The plot

Practice

The app

Practice - Your turn

  1. Create a new script: File > New File > R Script
  2. Paste the code below
  3. Save it
  4. Fill the ####### TO BE COMPLETED ######## sections
  5. Run it
# load packages
library(shiny)
library(dplyr)
library(ggplot2)

# load data
data_tdr = readRDS("../export/data_tdr.rds")

# define UI for the application
ui <- fluidPage(
  
#  # application title
#  titlePanel("TDR Data"),
#
#  # sidebar layout = sidebar panel + main panel
#  sidebarLayout(
#
#    # sidebar panel = sliderInput + radioButtons + checkboxGroupInput
#    sidebarPanel(
      
      ####### TO BE COMPLETED ########
      # sliderInput to choose the number of dives
      sliderInput(...),
      ################################
      
      # radioButtons to decide the color code
      radioButtons(inputId = "color_code",
                   label = "Color code:",
                   choices = c("Yes", "No"),
                   selected = c("No")),
      
      # checkboxGroupInput to select dive types
      checkboxGroupInput(inputId = "dive_type", 
                         label = "Dive types:", 
                         choices = unique(data_tdr$dive_type),
                         selected = unique(data_tdr$dive_type)),
#    ),
    
    # mainPanel = plotOutput
#    mainPanel(
      # plotOutput to display main_plot
      plotOutput(outputId = "main_plot")
#    )
#  )
)

# define server logic required to draw the plot
server <- function(input, output) {
  
  # store the plot
  output$main_plot <- renderPlot({
    
    # from data_tdr
    data_tdr %>% 
      # filter on the number of dives from the sliderInput in the ui
      filter(dive_number <= input$nb_dives) %>%
      
      ####### TO BE COMPLETED ########
      # filter on the dive type from the checkboxGroupInput in the ui
      
      ################################
      
      # initiate a plot
      ggplot(aes(x = datetime, 
                 y = depth,
                 group = dive_number))+
      # which going to be a geom_path = line plot
      geom_path(
        # if color_code == Yes
        mapping = if(input$color_code == "Yes"){
          # then use dive_type as color_code
          aes(col = dive_type)
        }
      ) 
#    +
#      ### everything below is optional ###
#      # tweak y axis
#      scale_y_reverse(
#        # a proper name
#        name = "Depth (m)",
#        # fix the limits, note: use rev because we reversed the y axis
#        limits = rev(range(data_tdr$depth))) +
#      # tweak x axis
#      scale_x_datetime(
#        # a proper name
#        name = "Time",
#        # ticks frequency
#        date_breaks = "20 mins",
#        # format of labels
#        date_labels = "%H:%M",
#        # position
#        position = "top",
#        # fix the limits
#        limits = range(data_tdr$datetime)) +
#      # tweak color
#      scale_color_manual(
#        # fix color for each dive type
#        values = c(Forage = "#00AFBB", 
#                   Transit = "#E7B800", 
#                   Drift = "#FC4E07")) +
#      # rename title of the legend
#      labs(col = "Dive Type") +
#      # choose a theme
#      theme_minimal() +
#      # and tweak it
#      theme(
#        # legend position
#        legend.position = "bottom",
#        # add arrow for x axis
#        axis.line.x = element_line(arrow = arrow(
#          ends = "last",
#          type = "closed",
#          length = unit(0.25, "npc"))),
#        # add arrow for y axis
#        axis.line.y = element_line(arrow = arrow(
#          ends = "first",
#          type = "closed",
#          length = unit(0.25, "npc"))))
  })
}

# Run the application 
shinyApp(ui = ui, server = server)

Publish

  • ShinyProxy
  • within a quarto/rmarkdown document

Alternatives

  • Plotly/Highcharts
  • Observable
  • PowerBI/Tableau

References

Wickham, Hadley. 2021. Mastering Shiny: Build Interactive Apps, Reports, and Dashboards Powered by r. 1st edition. Sebastopol, CA: O’Reilly Media.